import { isPrimitive, isString, isDef } from '@/utils/index'
import { watchEffect } from 'vue'
import { LOWCODE_COMPONENT_DATA } from './constant'

export const lowCodeAttr = ['type', 'body', 'api', 'initApi', 'actions', 'dialog'] // 低代码的属性，不赋值到组件上

export function commonFilterAttr(schema, excludes) {
  const attr = {}
  for (const key in schema) {
    const value = schema[key]
    if (!excludes.includes(key)) {
      attr[key] = value
    }
  }
  return attr
}

/**
 *
 * @param {*} schema
 * @param {*} reflectAttr 要替换属性名的对象
 */
export function filterAttr(schema, reflectAttr) {
  const attr = {}
  for (const key in schema) {
    if (!lowCodeAttr.includes(key)) {
      const value = schema[key]
      if (reflectAttr) {
        if (reflectAttr[key]) {
          attr[reflectAttr[key]] = value
        } else {
          attr[key] = value
        }
      } else {
        attr[key] = value
      }
    }
  }
  return attr
}

/**
 *
 * @param {*} excludeAttrs 不包括的属性
 * @param {*} schema
 * @param {*} reflectAttr 要替换属性名的对象
 */
export function filterAttrByExclude(excludeAttrs, schema, reflectAttr) {
  const attr = {}
  for (const key in schema) {
    if (!lowCodeAttr.includes(key)) {
      const value = schema[key]
      if (!excludeAttrs.includes(key)) {
        if (reflectAttr) {
          if (reflectAttr[key]) {
            attr[reflectAttr[key]] = value
          } else {
            attr[key] = value
          }
        } else {
          attr[key] = value
        }
      }
    }
  }
  return attr
}

/**
 *
 * @param {*} inCludeAttrs 包括的属性
 * @param {*} schema
 * @param {*} reflectAttr 要替换属性名的对象
 */
export function filterAttrByInclude(inCludeAttrs, schema, reflectAttr) {
  const attr = {}
  for (const key in schema) {
    if (!lowCodeAttr.includes(key)) {
      const value = schema[key]
      if (inCludeAttrs.includes(key)) {
        if (reflectAttr) {
          if (reflectAttr[key]) {
            attr[reflectAttr[key]] = value
          } else {
            attr[key] = value
          }
        } else {
          attr[key] = value
        }
      }
    }
  }
  return attr
}

export function plainFilterAttr(obj, arr) {
  const attr = {}
  for (const key in obj) {
    if (!arr.includes(key)) {
      const value = obj[key]
      attr[key] = value
    }
  }
  return attr
}

export function handleObject(paramsDatas, instance) {
  if (!paramsDatas) {
    return {}
  }
  for (const key in paramsDatas) {
    const value = paramsDatas[key]
    const rs = replaceValue(value, instance)
    paramsDatas[key] = rs
  }
  return paramsDatas
}

const reg = /(\$\{[a-zA-Z0-9_]+\})/g
export function replaceValue(str, instance) {
  if (!isString(str)) {
    return str
  }
  const result = findVarName(str)
  if (result === false) {
    return str
  }
  result.forEach((item) => {
    str = findLowCodeComponentDataAndReplace(str, item, instance)
  })
  return str
}

export function findVarName(str) {
  if (!isString(str)) {
    return false
  }
  const result = str.match(reg)
  if (!result || !result.length) {
    return false
  }
  return result
}

export function findLowCodeComponentDataAndReplace(str, placeholder, instance) {
  const rs = findVarByName(instance)
  if (rs === false) {
    return str
  }
  const lowCodeComponentData = rs.data
  const varName = placeholder.substring(2, placeholder.length - 1)
  if (Reflect.has(lowCodeComponentData, varName)) {
    const value = Reflect.get(lowCodeComponentData, varName)
    if (isPrimitive(value)) {
      return str.replaceAll(placeholder, value)
    } else {
      const rs = str.replaceAll(placeholder, JSON.stringify(value))
      try {
        return JSON.parse(rs)
      } catch (error) {
        console.error(error)
        return rs
      }
    }
  }

  const preInstance = rs.instance
  const parent = preInstance.parent
  if (parent) {
    return findLowCodeComponentDataAndReplace(str, placeholder, parent)
  }
  return str
}

export function findVarByName(instance, varName = LOWCODE_COMPONENT_DATA) {
  if (Reflect.has(instance.setupState, varName)) {
    return {
      data: Reflect.get(instance.setupState, varName),
      instance
    }
  }
  const parent = instance.parent
  if (parent) {
    return findVarByName(parent, varName)
  }
  return false
}

/**
 *
 * @param {*} str
 * @param {*} instance
 * @param {*} refVar
 * @param {*} resolver 是否解析字符串的值
 * @returns
 */
export function watchText(str, instance, refVar) {
  const vars = findVarName(str)
  if (vars === false) {
    return
  }
  vars.forEach((item) => {
    findVarAndWatch(str, item, instance, refVar)
  })
}

function findVarAndWatch(str, placeholder, instance, refVar) {
  const rs = findVarByName(instance)
  if (rs === false) {
    return
  }
  const lowCodeComponentData = rs.data
  const varName = placeholder.substring(2, placeholder.length - 1)
  if (Reflect.has(lowCodeComponentData, varName)) {
    watchEffect(() => {
      const value = lowCodeComponentData[varName]
      let _value = undefined
      if (isDef(value)) {
        _value = JSON.stringify(value)
      }
      const _str = str.replaceAll(placeholder, _value)
      try {
        refVar.value = eval(_str)
      } catch (error) {
        console.error(error)
      }
    })
    return
  }
  const preInstance = rs.instance
  const parent = preInstance.parent
  if (parent) {
    findVarAndWatch(str, placeholder, parent, refVar)
  }
}

export function downFileByUrl(url, fileName) {
  const a = document.createElement('a')
  a.setAttribute('target', '__blank')
  a.href = url
  a.download = fileName
  a.click()
}
